package com.holly.unit.deform.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.holly.unit.db.api.factory.PageFactory;
import com.holly.unit.db.api.factory.PageResultFactory;
import com.holly.unit.db.api.pojo.page.PageResult;
import com.holly.unit.deform.api.enums.PermissionTypeEnum;
import com.holly.unit.deform.api.pojo.rsp.DeformResult;
import com.holly.unit.deform.entity.DesignFormAuth;
import com.holly.unit.deform.entity.DesignFormData;
import com.holly.unit.deform.mapper.DeformAuthMapper;
import com.holly.unit.deform.pojo.ext.ExtActProcessNodeAuth;
import com.holly.unit.deform.util.DeformAuthUtil;
import com.holly.unit.query.api.context.QueryApiContext;
import com.holly.unit.system.api.UserServiceApi;
import com.holly.unit.system.api.pojo.user.UserLoginInfoDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类描述: 表单设计器字段权限表
 *
 * @author fxr
 * @version 1.0.0
 * @date 2022/4/7 8:29
 */
@Service
public class DeformAuthService extends ServiceImpl<DeformAuthMapper, DesignFormAuth> {

    @Autowired
    private UserServiceApi userServiceApi;






    /**
     * 根据 code 查询 auth
     *
     * @param desformCode
     * @param isGroup
     * @return
     */
    public List<DesignFormAuth> queryByCode(String desformCode, boolean isGroup){
        LambdaQueryWrapper<DesignFormAuth> queryWrapper = this.createWrapper(desformCode);
        if (isGroup) {
            queryWrapper.eq(DesignFormAuth::getAuthType, "1");
            //只查询表单字段授权
            queryWrapper.eq(DesignFormAuth::getPermissionType, "field");
        }
        return this.list(queryWrapper);
    }

    /**
     * 根据 code 查询 auth
     */
    public List<DesignFormAuth> queryByCode(String desformCode){
        return this.queryByCode(desformCode, false);
    }

    /**
     * 根据 desformCode 和 authComKey 查询单个权限
     *
     * @param desformCode
     * @param authComKey
     * @return
     */
    public List<DesignFormAuth> queryByCodeAndAuthComKey(String desformCode, String authComKey){
        return this.list(this.createWrapper(desformCode).eq(DesignFormAuth::getAuthComKey, authComKey));
    }

    /**
     * 根据 taskId 查询 auth【工作流中使用此接口】
     *
     * @param desformCode
     * @param taskId
     * @return
     */
    public List<DesignFormAuth> queryByTaskId(String desformCode, String taskId){
        List<ExtActProcessNodeAuth> list = this.baseMapper.selectByTaskId(desformCode, taskId);
        List<DesignFormAuth> result = new ArrayList<>(list.size());
        for (ExtActProcessNodeAuth item : list) {
            DesignFormAuth auth = new DesignFormAuth();
            auth.setDesformCode(desformCode);
            //判断是否子表的权限字段格式  cc_tou_su_product_62428::product_name
            String authField = item.getRuleCode();
            if(authField!=null && authField.indexOf("::")!=-1){
                auth.setSubKey(authField.substring(0,authField.indexOf("::")));
                auth.setSubTable(true);
                auth.setAuthField(authField.substring(authField.indexOf("::")+2));
            }else{
                auth.setAuthField(authField);
                auth.setSubTable(false);
            }
            auth.setAuthComKey(item.getDesformComKey());
            auth.setAuthTitle(item.getRuleName());

            // 1=显示，2=禁用
            String ruleType = item.getRuleType();

            // 0=无效，1=有效
            // 无效状态下，配置了显示权限的组件皆为隐藏状态，配置了禁用的组件皆为可编辑状态
            // 有效状态下，配置了显示权限的组件皆为显示状态，配置了禁用的组件皆为已禁用状态
            String status = item.getStatus();

            if ("0".equals(status)) {
                if ("1".equals(ruleType)) {
                    auth.setAuthScopeIsAll("N");
                } else {
                    auth.setAuthScopeIsAll("Y");
                }
            } else {
                if ("1".equals(ruleType)) {
                    auth.setAuthScopeIsAll("Y");
                } else {
                    auth.setAuthScopeIsAll("N");
                }
            }
            auth.setAuthType(ruleType);
            auth.setPermissionType("field");
            auth.setStatus(1);

            result.add(auth);
        }
        return result;
    }

    /**
     * 修改多个权限控制
     *
     * @param auths
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatch(List<DesignFormAuth> auths){

        for (DesignFormAuth auth : auths) {
            LambdaQueryWrapper<DesignFormAuth> queryWrapper = new LambdaQueryWrapper<>();
            if (StrUtil.isEmpty(auth.getId())) {
                queryWrapper.eq(DesignFormAuth::getDesformCode, auth.getDesformCode());
                queryWrapper.eq(DesignFormAuth::getAuthComKey, auth.getAuthComKey());
                if (!StrUtil.isEmpty(auth.getAuthType())) {
                    queryWrapper.eq(DesignFormAuth::getAuthType, auth.getAuthType());
                }
            } else {
                queryWrapper.eq(DesignFormAuth::getId, auth.getId());
            }
            this.update(auth, queryWrapper);
        }
        return true;

    }

    /**
     * 根据用户名获取用户信息以及拥有的部门、角色
     *
     * @param username
     * @return
     */
    public JSONObject getUserInfoByUsername(String username){
        UserLoginInfoDTO userInfo = userServiceApi.getUserLoginInfo(username);
        if (userInfo == null) {
            throw new RuntimeException("用户不存在");
        }

        Long userId = userInfo.getLoginUser().getUserId();
        Long orgId = userInfo.getLoginUser().getOrganizationId();
        List<Long> roles = userServiceApi.getUserRoleIdList(userId);
        List<Long> departs = new ArrayList<>();
        departs.add(orgId);
        JSONObject json = new JSONObject(3);
        json.put("userInfo", userInfo);
        json.put("roles", roles);
        json.put("departs", departs);
        return json;
    }

    /**
     * 初始化某个字段的权限
     *
     * @param auth
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean initialAuthInfo(DesignFormAuth auth){
        auth.setAuthScopeIsAll("Y");
        if (auth.getSubTable() == null) {
            auth.setSubTable(false);
        }
        auth.setStatus(1);
        auth.setPermissionType("field");

        List<DesignFormAuth> authList = new ArrayList<>();

        // 添加可见权限
        DesignFormAuth authTemp = new DesignFormAuth();
        BeanUtil.copyProperties(auth, authTemp);
        authTemp.setAuthType("1");
        authList.add(authTemp);

        // 添加可编辑权限
        authTemp = new DesignFormAuth();
        BeanUtil.copyProperties(auth, authTemp);
        authTemp.setAuthType("2");
        authList.add(authTemp);

        return this.saveBatch(authList);
    }

    /**
     * 检查 permissionType 是否合法
     *
     * @param permissionType
     * @return
     */
    public boolean checkPermissionType(String permissionType){
        PermissionTypeEnum type = PermissionTypeEnum.getByValue(permissionType);
        if (type != null) {
            return true;
        }
        throw new RuntimeException("不识别的permissionType值");
    }

    /**
     * 查询分页内容
     *
     * @param pageNo
     * @param pageSize
     * @param wrapper
     * @return
     */
    public DeformResult pageList(Integer pageNo, Integer pageSize, Wrapper<DesignFormAuth> wrapper){
        DeformResult deformResult = new DeformResult();
        if (pageNo == -1) {
            IPage<DesignFormAuth> pageList = new Page<>();
            List<DesignFormAuth> list = super.list(wrapper);
            pageList.setRecords(list);
            pageList.setTotal(list.size());
            deformResult.setResult(pageList);
        } else {
            Page<DesignFormAuth> page = this.page(PageFactory.defaultPage(), wrapper);
            PageResult<DesignFormAuth> pageData = PageResultFactory.createPageResult(page);
            deformResult.setResult(pageData);

        }
        return deformResult;
    }

    /**
     * 根据 permissionType 新增
     *
     * @param auth
     * @param permissionType
     * @return
     */
    public boolean addAuthByPermissionType(DesignFormAuth auth, String permissionType){
        if (checkPermissionType(permissionType)) {
            auth.setPermissionType(permissionType);
            return super.save(auth);
        }
        return false;
    }

    /**
     * 根据 permissionType 修改
     *
     * @param auth
     * @param permissionType
     * @return
     */
    public boolean editAuthByPermissionType(DesignFormAuth auth, String permissionType){
        if (checkPermissionType(permissionType)) {
            auth.setPermissionType(permissionType);
            if (PermissionTypeEnum.BUTTON.getValue().equals(permissionType)) {
                return this.addOrEditButtonAuth(auth);
            } else {
                DesignFormAuth designFormAuthEntity = super.getById(auth.getId());
                if (designFormAuthEntity == null) {
                    throw new RuntimeException("未找到对应实体");
                } else {
                    return super.updateById(auth);
                }
            }
        }
        return false;
    }

    /**
     * 添加或删除按钮权限
     */
    public boolean addOrEditButtonAuth(DesignFormAuth auth) {
        LambdaQueryWrapper<DesignFormAuth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DesignFormAuth::getPermissionType, auth.getPermissionType());
        queryWrapper.eq(DesignFormAuth::getDesformId, auth.getDesformId());
        queryWrapper.eq(DesignFormAuth::getDesformCode, auth.getDesformCode());
        queryWrapper.eq(DesignFormAuth::getAuthField, auth.getAuthField());
        DesignFormAuth entity = super.getOne(queryWrapper);
        if (entity == null) {
            if (auth.getStatus() == null) {
                auth.setStatus(1);
            }
            return super.save(auth);
        } else {
            return super.update(auth, queryWrapper);
        }
    }

    /**
     * 查询按钮权限
     *
     * @param desformCode
     * @param username
     * @return
     */
    public JSONObject queryButtonsAuth(String desformCode, String username){
        LambdaQueryWrapper<DesignFormAuth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DesignFormAuth::getPermissionType, PermissionTypeEnum.BUTTON.getValue());
        queryWrapper.eq(DesignFormAuth::getDesformCode, desformCode);
        queryWrapper.eq(DesignFormAuth::getStatus, 1);
        List<DesignFormAuth> entityList = super.list(queryWrapper);

        JSONObject userInfo = this.getUserInfoByUsername(username);
        return DeformAuthUtil.checkButtonsAuth(entityList, userInfo);
    }

    /**
     * 查询数据权限
     *
     * @param desformCode
     * @param username
     * @param superQueryList
     * @return
     */
    public JSONArray queryDataAuth(String desformCode, String username, QueryWrapper<DesignFormData> queryWrapper, JSONArray superQueryList){
        LambdaQueryWrapper<DesignFormAuth> getQueryWrapper = new LambdaQueryWrapper<>();
        getQueryWrapper.eq(DesignFormAuth::getPermissionType, PermissionTypeEnum.DATA.getValue());
        getQueryWrapper.eq(DesignFormAuth::getDesformCode, desformCode);
        getQueryWrapper.eq(DesignFormAuth::getStatus, 1);
        List<DesignFormAuth> entityList = super.list(getQueryWrapper);

        JSONObject allUserInfo = this.getUserInfoByUsername(username);
        JSONObject userInfo = allUserInfo.getJSONObject("userInfo");

        for (DesignFormAuth auth : entityList) {
            // 检查权限
            if (!DeformAuthUtil.checkOneDesformAuth(auth, allUserInfo)) {
                continue;
            }
            JSONObject queryItem = null;
            String field = auth.getAuthField();
            String val = auth.getAuthValue();
            // 替换 #{xxx} 变量
            val = QueryApiContext.me().getSqlRuleValue(val);

            // 判断是不是系统内置字段，如果是就不走 es 的查询
            if ("create_by".equals(field)
                    || "create_time".equals(field)
                    || "update_by".equals(field)
                    || "update_time".equals(field)
                    ) {
                queryWrapper.eq(field, val);
            } else {
                boolean findIt = false;
                for (int i = 0; i < superQueryList.size(); i++) {
                    JSONObject temp = superQueryList.getJSONObject(i);
                    // 如果用户选择的高级查询和数据权限有冲突，那就走数据权限的规则
                    if (field.equals(temp.getString("field"))) {
                        // 直接覆盖高级查询的规则
                        queryItem = temp;
                        findIt = true;
                        break;
                    }
                }

                if (queryItem == null) {
                    queryItem = new JSONObject();
                }

                queryItem.put("field", field);
                queryItem.put("rule", auth.getAuthType());
                queryItem.put("val", val);

                if (!findIt) {
                    superQueryList.add(queryItem);
                }
            }
        }
        return superQueryList;
    }

    /**
     * 根据不同的授权类型，查询不同的数据，做出不同的处理
     *
     * @param authScopeField 授权字段名称
     * @param authScopeCode  授权字段值
     * @param designFormAuth
     * @param permissionType
     * @param desformCode
     * @param request
     * @return
     */
    public DeformResult buildResultByPermissionType(String authScopeField, String authScopeCode, DesignFormAuth designFormAuth, String permissionType, String desformCode, HttpServletRequest request){
        PermissionTypeEnum perType = PermissionTypeEnum.getByValue(permissionType);
        if (perType != null) {
            // 为了防止查询条件生成器重复生成条件语句，所以设置为 null
            designFormAuth.setDesformCode(null);
            designFormAuth.setPermissionType(null);
            QueryWrapper<DesignFormAuth> queryWrapper = QueryApiContext.me().initQueryWrapper(designFormAuth, request.getParameterMap());
            queryWrapper.eq("desform_code", desformCode);
            queryWrapper.eq("permission_type", permissionType);
            // 根据不同的授权类型，查询不同的数据，做出不同的处理
            if (PermissionTypeEnum.DATA == perType || PermissionTypeEnum.FIELD == perType) {
                return this.buildDataFieldResult(queryWrapper, authScopeField, authScopeCode, perType);
            } else if (PermissionTypeEnum.BUTTON == perType) {
                return this.buildButtonResult(queryWrapper, authScopeField, authScopeCode);
            }
        }
        return DeformResult.error("不识别的permissionType值：" + permissionType);
    }

    /**
     * 数据权限、字段权限适用
     *
     * @param queryWrapper
     * @param authScopeField
     * @param authScopeCode
     * @return
     */
    public DeformResult buildDataFieldResult(QueryWrapper<DesignFormAuth> queryWrapper, String authScopeField, String authScopeCode, PermissionTypeEnum perType){
        queryWrapper.eq("status", 1);
        // Step.1 查询出所有数据
        List<DesignFormAuth> allList = super.list(queryWrapper);
        // Step.2 查询出已授权的数据
        queryWrapper.and(i -> spliceAuthScopeWrapper(i, authScopeField, authScopeCode));
        List<DesignFormAuth> list = super.list(queryWrapper);
        // Step.3 合并两个数据并返回（返回值最小化）
        JSONArray records = new JSONArray();
        for (DesignFormAuth auth : allList) {
            JSONObject temp = new JSONObject(3);
            temp.put("key", auth.getId());
            String title = auth.getAuthTitle();
            // 字段权限需要在标题上处理下可见或可编辑
            if (PermissionTypeEnum.FIELD == perType) {
                if ("1".equals(auth.getAuthType())) {
                    title += "（可见）";
                } else {
                    title += "（可编辑）";

                }
            }
            temp.put("title", title);
            temp.put("authField", auth.getAuthField());
            temp.put("scopeValue", auth.getAuthScopeRolesVal());
            temp.put("authScopeIsAll", auth.getAuthScopeIsAll());
            records.add(temp);
        }
        JSONObject result = new JSONObject(2);
        result.put("records", records);
        result.put("targetKeys", list.stream().map(DesignFormAuth::getId).collect(Collectors.toList()));
        return DeformResult.ok(result);
    }

    /**
     * 构造返回值，仅按钮权限适用
     *
     * @param queryWrapper
     * @param authScopeField
     * @param authScopeCode
     * @return
     */
    public DeformResult buildButtonResult(QueryWrapper<DesignFormAuth> queryWrapper, String authScopeField, String authScopeCode){
        // Step.1 查询出所有数据
        List<DesignFormAuth> allDbList = super.list(queryWrapper);
        List<DesignFormAuth> allButtonList = DeformAuthUtil.getNewButtonList();
        // 由于按钮有可能没有存到数据库，所以查出来的不一定是全部的数据，还需要合并一下
        List<DesignFormAuth> assignButtonList = DeformAuthUtil.assignButtonList(allButtonList, allDbList);
        // Step.2 查询出已授权的数据
        queryWrapper.and(i -> spliceAuthScopeWrapper(i, authScopeField, authScopeCode));
        List<DesignFormAuth> list = super.list(queryWrapper);
        // Step.3 合并两个数据并返回（返回值最小化）
        JSONArray records = new JSONArray();
        assignButtonList.forEach(auth -> {
            if (auth.getStatus() == 1) {
                JSONObject temp = new JSONObject(5);
                temp.put("key", auth.getId());
                temp.put("title", auth.getAuthTitle());
                temp.put("authField", auth.getAuthField());
                temp.put("scopeValue", auth.getAuthScopeRolesVal());
                temp.put("authScopeIsAll", auth.getAuthScopeIsAll());
                records.add(temp);
            }
        });
        JSONObject result = new JSONObject(2);
        result.put("records", records);
        result.put("targetKeys", list.stream().map(DesignFormAuth::getId).collect(Collectors.toList()));
        return DeformResult.ok(result);
    }

    /**
     * 拼接逗号分隔形式存储的值所有可能出现的情况
     */
    public QueryWrapper<DesignFormAuth> spliceAuthScopeWrapper(QueryWrapper<DesignFormAuth> i, String fieldName, String code){
        return i.eq(fieldName, code)
                .or().like(fieldName, "," + code + ",")
                .or().likeLeft(fieldName, "," + code)
                .or().likeRight(fieldName, code + ",");
    }

    /***************************************************内部工具类*****************************************************/

    private LambdaQueryWrapper<DesignFormAuth> createWrapper(String desformCode) {
        LambdaQueryWrapper<DesignFormAuth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DesignFormAuth::getDesformCode, desformCode);
        return queryWrapper;
    }
}
